home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / tiff / tools / rgb2ycbcr.c < prev    next >
C/C++ Source or Header  |  1992-02-20  |  10KB  |  368 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Header: /usr/people/sam/tiff/tools/RCS/rgb2ycbcr.c,v 1.9 92/02/21 15:52:29 sam Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Copyright (c) 1991, 1992 Sam Leffler
  7.  * Copyright (c) 1991, 1992 Silicon Graphics, Inc.
  8.  *
  9.  * Permission to use, copy, modify, distribute, and sell this software and 
  10.  * its documentation for any purpose is hereby granted without fee, provided
  11.  * that (i) the above copyright notices and this permission notice appear in
  12.  * all copies of the software and related documentation, and (ii) the names of
  13.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  14.  * publicity relating to the software without the specific, prior written
  15.  * permission of Sam Leffler and Silicon Graphics.
  16.  * 
  17.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  18.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  19.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  20.  * 
  21.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  22.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  23.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  24.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  25.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  26.  * OF THIS SOFTWARE.
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include "tiffio.h"
  31. #include <string.h>
  32.  
  33. typedef    unsigned char u_char;
  34. typedef    unsigned short u_short;
  35. typedef    unsigned int u_int;
  36. typedef    unsigned long u_long;
  37.  
  38. #define    streq(a,b)    (strcmp(a,b) == 0)
  39. #define    CopyField(tag, v) \
  40.     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
  41.  
  42. #define    howmany(x, y)    (((x)+((y)-1))/(y))
  43. #define    roundup(x, y)    (howmany(x,y)*((u_int)(y)))
  44.  
  45. #define    LumaRed        ycbcrCoeffs[0]
  46. #define    LumaGreen    ycbcrCoeffs[1]
  47. #define    LumaBlue    ycbcrCoeffs[2]
  48.  
  49. u_short    compression = COMPRESSION_LZW;
  50. long    rowsperstrip = -1;
  51.  
  52. u_short    horizSubSampling = 2;        /* YCbCr horizontal subsampling */
  53. u_short    vertSubSampling = 2;        /* YCbCr vertical subsampling */
  54. float    ycbcrCoeffs[3] = { .299, .587, .114 };
  55. /* default coding range is CCIR Rec 601-1 with no headroom/footroom */
  56. float    refBlackWhite[6] = { 0., 255., 128., 255., 128., 255. };
  57.  
  58. static    int tiffcvt();
  59. static    void usage();
  60. static    void setupLumaTables();
  61.  
  62. main(argc, argv)
  63.     char *argv[];
  64. {
  65.     TIFF *in, *out;
  66.     int c;
  67.     extern int optind;
  68.     extern char *optarg;
  69.  
  70.     while ((c = getopt(argc, argv, "c:h:r:v:z")) != -1)
  71.         switch (c) {
  72.         case 'c':
  73.             if (streq(optarg, "none"))
  74.                 compression = COMPRESSION_NONE;
  75.             else if (streq(optarg, "packbits"))
  76.                 compression = COMPRESSION_PACKBITS;
  77.             else if (streq(optarg, "lzw"))
  78.                 compression = COMPRESSION_LZW;
  79.             else
  80.                 usage();
  81.             break;
  82.         case 'h':
  83.             horizSubSampling = atoi(optarg);
  84.             break;
  85.         case 'v':
  86.             vertSubSampling = atoi(optarg);
  87.             break;
  88.         case 'r':
  89.             rowsperstrip = atoi(optarg);
  90.             break;
  91.         case 'z':    /* CCIR Rec 601-1 w/ headroom/footroom */
  92.             refBlackWhite[0] = 16.;
  93.             refBlackWhite[1] = 235.;
  94.             refBlackWhite[2] = 128.;
  95.             refBlackWhite[3] = 240.;
  96.             refBlackWhite[4] = 128.;
  97.             refBlackWhite[5] = 240.;
  98.             break;
  99.         case '?':
  100.             usage();
  101.             /*NOTREACHED*/
  102.         }
  103.     if (argc - optind < 2)
  104.         usage();
  105.     out = TIFFOpen(argv[argc-1], "w");
  106.     if (out == NULL)
  107.         exit(-2);
  108.     setupLumaTables();
  109.     for (; optind < argc-1; optind++) {
  110.         in = TIFFOpen(argv[optind], "r");
  111.         if (in != NULL) {
  112.             do {
  113.                 if (!tiffcvt(in, out) ||
  114.                     !TIFFWriteDirectory(out))
  115.                     goto bad;
  116.             } while (TIFFReadDirectory(in));
  117.             (void) TIFFClose(in);
  118.         }
  119.     }
  120.     (void) TIFFClose(out);
  121.     exit(0);
  122. bad:
  123.     unlink(TIFFFileName(out));
  124.     exit(1);
  125. }
  126.  
  127. float    *lumaRed;
  128. float    *lumaGreen;
  129. float    *lumaBlue;
  130. float    D1, D2;
  131. int    Yzero;
  132.  
  133. static float*
  134. setupLuma(c)
  135.     float c;
  136. {
  137.     float *v = (float *)malloc(256 * sizeof (float));
  138.     int i;
  139.     for (i = 0; i < 256; i++)
  140.         v[i] = c * i;
  141.     return (v);
  142. }
  143.  
  144. static unsigned
  145. V2Code(f, RB, RW, CR)
  146.     float f;
  147.     float RB, RW;
  148.     int CR;
  149. {
  150.     unsigned int c = (unsigned int)((((f)*(RW-RB)/CR)+RB)+.5);
  151.     return (c > 255 ? 255 : c);
  152. }
  153.  
  154. static void
  155. setupLumaTables()
  156. {
  157.     lumaRed = setupLuma(LumaRed);
  158.     lumaGreen = setupLuma(LumaGreen);
  159.     lumaBlue = setupLuma(LumaBlue);
  160.     D1 = 1./(2 - 2*LumaBlue);
  161.     D2 = 1./(2 - 2*LumaRed);
  162.     Yzero = V2Code(0, refBlackWhite[0], refBlackWhite[1], 255);
  163. }
  164.  
  165. static void
  166. cvtClump(op, raster, ch, cw, w)
  167.     u_char *op;
  168.     u_long *raster;
  169.     u_int ch, cw;
  170.     u_long w;
  171. {
  172.     float Y, Cb = 0, Cr = 0;
  173.     int j, k;
  174.     /*
  175.      * Convert ch-by-cw block of RGB
  176.      * to YCbCr and sample accordingly.
  177.      */
  178.     for (k = 0; k < ch; k++) {
  179.         for (j = 0; j < cw; j++) {
  180.             u_long RGB = (raster - k*w)[j];
  181.             Y = lumaRed[TIFFGetR(RGB)] +
  182.                 lumaGreen[TIFFGetG(RGB)] +
  183.                 lumaBlue[TIFFGetB(RGB)];
  184.             /* accumulate chrominance */
  185.             Cb += (TIFFGetB(RGB) - Y) * D1;
  186.             Cr += (TIFFGetR(RGB) - Y) * D2;
  187.             /* emit luminence */
  188.             *op++ = V2Code(Y,
  189.                 refBlackWhite[0], refBlackWhite[1], 255);
  190.         }
  191.         for (; j < horizSubSampling; j++)
  192.             *op++ = Yzero;
  193.     }
  194.     for (; k < vertSubSampling; k++) {
  195.         for (j = 0; j < horizSubSampling; j++)
  196.             *op++ = Yzero;
  197.     }
  198.     /* emit sampled chrominance values */
  199.     *op++ = V2Code(Cb / (ch*cw), refBlackWhite[2], refBlackWhite[3], 127);
  200.     *op++ = V2Code(Cr / (ch*cw), refBlackWhite[4], refBlackWhite[5], 127);
  201. }
  202. #undef LumaRed
  203. #undef LumaGreen
  204. #undef LumaBlue
  205. #undef V2Code
  206.  
  207. /*
  208.  * Convert a strip of RGB data to YCbCr and
  209.  * sample to generate the output data.
  210.  */
  211. static
  212. cvtStrip(op, raster, nrows, width)
  213.     u_char *op;
  214.     u_long *raster;
  215.     u_long nrows, width;
  216. {
  217.     long x, y;
  218.     int clumpSize = vertSubSampling * horizSubSampling + 2;
  219.     u_long *tp;
  220.  
  221.     for (; nrows >= vertSubSampling; nrows -= vertSubSampling) {
  222.         tp = raster;
  223.         for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
  224.             cvtClump(op, tp,
  225.                 vertSubSampling, horizSubSampling, width);
  226.             op += clumpSize;
  227.             tp += horizSubSampling;
  228.         }
  229.         if (x > 0) {
  230.             cvtClump(op, tp, vertSubSampling, x, width);
  231.             op += clumpSize;
  232.         }
  233.         raster -= vertSubSampling*width;
  234.     }
  235.     if (nrows > 0) {
  236.         tp = raster;
  237.         for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
  238.             cvtClump(op, tp, nrows, horizSubSampling, width);
  239.             op += clumpSize;
  240.             tp += horizSubSampling;
  241.         }
  242.         if (x > 0)
  243.             cvtClump(op, tp, nrows, x, width);
  244.     }
  245. }
  246.  
  247. static int
  248. cvtRaster(tif, raster, width, height)
  249.     TIFF *tif;
  250.     u_long *raster;
  251.     u_long width, height;
  252. {
  253.     long y;
  254.     u_int strip = 0;
  255.     u_int cc;
  256.     u_char *buf;
  257.     u_long rwidth = roundup(width, horizSubSampling);
  258.     u_long rheight = roundup(height, vertSubSampling);
  259.     u_long nrows = (rowsperstrip > rheight ? rheight : rowsperstrip);
  260.  
  261.     cc = nrows*rwidth +
  262.         2*((nrows*rwidth) / (horizSubSampling*vertSubSampling));
  263.     buf = (u_char *)malloc(cc);
  264.     for (y = height; y > 0; y -= nrows) {
  265.         u_long nr = (y > nrows ? nrows : y);
  266.         cvtStrip(buf, raster + (y-1)*width, nr, width, cc);
  267.         if (nr % vertSubSampling) {
  268.             u_int acc;
  269.             /*
  270.              * Short strip, zero data after image.
  271.              */
  272.             nr = roundup(nr, vertSubSampling);
  273.             acc = nr*rwidth +
  274.                 2*((nr*rwidth)/(horizSubSampling*vertSubSampling));
  275.             bzero(buf+acc, cc - acc);
  276.         }
  277.         if (!TIFFWriteEncodedStrip(tif, strip++, buf, cc)) {
  278.             free(buf);
  279.             return (0);
  280.         }
  281.     }
  282.     free(buf);
  283.     return (1);
  284. }
  285.  
  286. static int
  287. tiffcvt(in, out)
  288.     TIFF *in, *out;
  289. {
  290.     u_long width, height;        /* image width & height */
  291.     u_long *raster;            /* retrieve RGBA image */
  292.     short shortv;
  293.     float floatv;
  294.     char *stringv;
  295.     u_long longv;
  296.  
  297.     TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
  298.     TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
  299.     raster = (u_long *)malloc(width * height * sizeof (u_long));
  300.     if (raster == 0) {
  301.         TIFFError(TIFFFileName(in), "No space for raster buffer");
  302.         return (0);
  303.     }
  304.     if (!TIFFReadRGBAImage(in, width, height, raster, 0)) {
  305.         free(raster);
  306.         return (0);
  307.     }
  308.  
  309.     CopyField(TIFFTAG_SUBFILETYPE, longv);
  310.     TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
  311.     TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
  312.     TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
  313.     TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
  314.     TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
  315.     CopyField(TIFFTAG_FILLORDER, shortv);
  316.     TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
  317.     TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
  318.     CopyField(TIFFTAG_XRESOLUTION, floatv);
  319.     CopyField(TIFFTAG_YRESOLUTION, floatv);
  320.     CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
  321.     TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  322.     if (rowsperstrip <= 0)
  323.         rowsperstrip = (8*1024)/TIFFScanlineSize(out);
  324.     rowsperstrip = roundup(rowsperstrip, vertSubSampling);
  325.     TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
  326.     { char buf[2048];
  327.       char *cp = strrchr(TIFFFileName(in), '/');
  328.       if (!cp)
  329.         cp = TIFFFileName(in);
  330.       else
  331.         cp++;
  332.       sprintf(buf, "YCbCr conversion of %s", cp);
  333.       TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, buf);
  334.     }
  335.     TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFVersion);
  336.     CopyField(TIFFTAG_DOCUMENTNAME, stringv);
  337.  
  338.     TIFFSetField(out, TIFFTAG_REFERENCEBLACKWHITE, refBlackWhite);
  339.     TIFFSetField(out, TIFFTAG_YCBCRSUBSAMPLING,
  340.         horizSubSampling, vertSubSampling);
  341.     TIFFSetField(out, TIFFTAG_YCBCRPOSITIONING, YCBCRPOSITION_CENTERED);
  342.     TIFFSetField(out, TIFFTAG_YCBCRCOEFFICIENTS, ycbcrCoeffs);
  343.  
  344.     return (cvtRaster(out, raster, width, height));
  345. }
  346.  
  347. static char* usageMsg[] = {
  348.     "usage: rgb2ycbcr [-c comp] [-r rows] [-h N] [-v N] input... output\n",
  349.     "where comp is one of the following compression algorithms:\n",
  350.     " lzw\t\tLempel-Ziv & Welch encoding\n",
  351.     " packbits\tPackBits encoding\n",
  352.     " none\t\tno compression\n",
  353.     "and the other options are:\n",
  354.     " -r\trows/strip\n",
  355.     " -h\thorizontal sampling factor (1,2,4)\n",
  356.     " -v\tvertical sampling factor (1,2,4)\n",
  357.     NULL
  358. };
  359.  
  360. static void
  361. usage()
  362. {
  363.     int i;
  364.     for (i = 0; usageMsg[i]; i++)
  365.         fprintf(stderr, "%s", usageMsg[i]);
  366.     exit(-1);
  367. }
  368.